package com.zhaoc.ioc.container;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import com.zhaoc.ioc.Inject;

/** 
 * <br>类 名: AbstractApplicationContext
 * <br>描 述: 容器注册的基本实现
 * <br>作 者: zhaoc
 * <br>创 建: 2015年8月18日
 * <br>版 本: v1.0.0
 * <br>
 * <br>历 史: (版本) 作者 时间 注释 
 */
public abstract class AbstractApplicationContext implements ApplicationContext {
	/** 内部工厂集合 延迟加载仓库 */
	static final Map<Key<?>, InternalFactory> factorys = new HashMap<Key<?>, InternalFactory>();
	/** 单实例仓库 */
	static final Map<Key<?>, Object> staticRepository = new HashMap<Key<?>, Object>();
	/** 单例占位符 */
	static final Object placeHolder = new Object();
	
	/** 
	 * <p>容器注册
	 * <p>注册到容器中的是接口类型与类的类型，此时并没有创建实例对象，只是封装了内部工厂
	 * @param interfaceType 接口类型
	 * @param name 注册名
	 * @param classType 实际类型 类类型
	 * @param type 实例化类型 
	 */
	@Override
	public <T> void inject(Class<T> interfaceType, String name,
			final Class<? extends T> classType, final ScopeTypeEnum type) {
		if(type == null) {
			throw new NullPointerException("initialzation type can not be null");
		}
		factorys.put(Key.newInstance(name, interfaceType), new InternalFactory() { /* 构建内部工厂 */
			@Override
			public T create(Context context) {
				return type.create(classType, context); /* 使用枚举的构建方法 面向对象的设计思想 */
			}
		});
		if(type == ScopeTypeEnum.SINGLETON) { /* 若创建模式为 单例  则 使用单例占位符补位 */
			staticRepository.put(Key.newInstance(name, interfaceType), placeHolder);
		}
	}
	/**
	 * 获得容器中的实例
	 * <p>延迟加载 意义在于注册到容器中的类并没有创建实例，在获取类实例的时候才创建
	 * 
	 * @param interfaceType 接口类型 注册到容器中的 子类 可为多个，获取实例时 使用 接口类型与注册名称即可
	 * @param name 注册名称 与 接口类型 为 联合主键
	 */
	@Override
	public <T> T getBean(final Class<T> interfaceType, final String name) {
		return callback(new CallBackable() {
			@Override
			public T create(Context context) {
				return getInstance(interfaceType, name, context); /* 获得具体的实例 */
			}
		}, interfaceType, name);
	}
	
	/**
	 * <p>实例的创建过程
	 * @param callback 具体创建实例的句柄
	 * @param keyInterfaceType 接口类型
	 * @param keyName 注册名称
	 * @return
	 */
	<T> T callback(CallBackable callback, Class<T> keyInterfaceType, String keyName)  {
		Context context = new Context("create root context");
		Key<?> key = Key.newInstance(keyName, keyInterfaceType); /* 创建联合主键 */
		Object staticObject = staticRepository.get(key); /* 查找单实例 */
		T instance = staticObject != placeHolder ? (T) staticObject : null;
		if(instance != null) {
			return instance; /* 返回单实例 */
		}
		instance = callback.create(context); /* 创建新实例 */
		Field[] fields = instance.getClass().getDeclaredFields();
		for(Field field : fields) {
			if(field.isAnnotationPresent(Inject.class)) {/* 依赖注入的实现 */
				Class<?> interfaceType = field.getType();
				Inject inject = field.getAnnotation(Inject.class);
				String name = field.getName();
				if(!inject.value().equals(Inject.DEFAULT_NAME)) {
					name = inject.value();
				}
				field.setAccessible(true);
				try {
					field.set(instance, getBean(interfaceType, name));
				} catch (Exception e) {
					System.out.println("reflect field failure !");
				}
			}
		}
		if(staticRepository.containsKey(key)) {
			staticRepository.put(key, instance);/* 单实例仓库缓存 */
		}
		return instance; 
	}
	/***
	 * <p> 具体实例创建的实现，当前类具备实例化的能力 此处将其抽象出来 为增加灵活性
	 * @param interfaceType 接口类型
	 * @param name 注册名
	 * @param context 创建功能上下文
	 * @return
	 */
	abstract <T> T getInstance(Class<T> interfaceType, String name, Context context); 
	
	interface CallBackable {
		<T> T create(Context context);
	}
	
	interface InternalFactory {
		<T> T create(Context context);
	}
}

/** 
 * <br>类 名: Key
 * <br>描 述: 联合主键的定义
 * <br>作 者: zhaoc
 * <br>创 建: 2015年8月18日
 * <br>版 本: v1.0.0
 * <br>
 * <br>历 史: (版本) 作者 时间 注释 
 */
class Key<T> {
	/** 接口类型 */
	Class<T> interfaceType;
	/** 注册名 */
	String name;
	public Key() { }
	
	public Key(String name, Class<T> interfaceType) {
		this.name = name;
		this.interfaceType = interfaceType;
	}
	public Class<?> getInterfaceType() {
		return interfaceType;
	}
	public void setInterfaceType(Class<T> interfaceType) {
		this.interfaceType = interfaceType;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	/***
	 * 此处的HashCode必须要重写 典型的重写hashcode 实现自定义的比较
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((interfaceType == null) ? 0 : interfaceType.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Key other = (Key) obj;
		if (interfaceType == null) {
			if (other.interfaceType != null)
				return false;
		} else if (!interfaceType.equals(other.interfaceType))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	static <T> Key<T> newInstance(String name, Class<T> interfaceType) {
		return new Key<T>(name, interfaceType);
	}
}

